package com.nut.article.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nut.article.api.req.SaveSortReq;
import com.nut.article.cache.CacheInMap;
import com.nut.article.common.Constants;
import com.nut.article.common.Holder;
import com.nut.article.common.Result;
import com.nut.article.entity.*;
import com.nut.article.interceptor.UserJwt;
import com.nut.article.mapper.ArticleDetailMapper;
import com.nut.article.mapper.ArticleLikesMapper;
import com.nut.article.mapper.ArticleMapper;
import com.nut.article.mapper.TagArticleMapper;
import com.nut.article.service.ArticleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private CacheInMap cacheInMap;

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private TagArticleMapper tagArticleMapper;

    @Autowired
    private ArticleDetailMapper articleDetailMapper;

    @Autowired
    private ArticleLikesMapper articleLikesMapper;

    @Autowired
    private ValueOperations<String, Object> valueOperations;

    @Override
    public Result<String> getDownInfoById(Serializable id) {
        ArticleDetail detail = articleDetailMapper.selectById(id);
        if (detail == null) {
            return Result.fail("找不到下载地址");
        }
        return Result.ok(detail.getDownAddress());
    }

    @Override
    public List<ArticleVo> hotList() {
        Object cache = cacheInMap.findCache(hotList, () -> {
            return articleMapper.selectHotList();
        }, 30, TimeUnit.MINUTES);

        return (List<ArticleVo>) cache;
    }

    @Override
    public List<ArticleVo> topList() {
        Object cache = cacheInMap.findCache(topList, () -> {
            return articleMapper.selectTopList();
        }, 30, TimeUnit.MINUTES);

        return (List<ArticleVo>) cache;
    }

    @Override
    public List<ArticleVo> newList() {
        Object cache = cacheInMap.findCache(newList, () -> {
            return articleMapper.selectNewList();
        }, 30, TimeUnit.MINUTES);

        return (List<ArticleVo>) cache;
    }

    @Override
    public List<ArticleVo> sideList() {

        Object cache = cacheInMap.findCache(sideList, () -> {
            return articleMapper.selectSideList();
        }, 30, TimeUnit.MINUTES);

        return (List<ArticleVo>) cache;
    }

    @Override
    public List<ArticleVo> searchList(String keywords) {
        List<ArticleVo> list = articleMapper.searchList(keywords);
        return list;
    }

    @Override
    public Result saveSort(SaveSortReq saveSortReq) {

        String types = saveSortReq.getType();
        String[] ids = saveSortReq.getIds();

        articleMapper.resetSort(types);

        for (int i = 0; i < ids.length; i++) {

            Article update = new Article();
            update.setId(Integer.valueOf(ids[i]));

            int score = i + 1;
            if (types.equals(HOT)) {
                update.setHot(score);
            } else if (types.equals(TOP)) {
                update.setTop(score);
            } else if (types.equals(SIDE)) {
                update.setSide(score);
            }
            articleMapper.updateById(update);
        }

        if (types.equals(HOT)) {
            cacheInMap.removeKey(hotList);
        } else if (types.equals(TOP)) {
            cacheInMap.removeKey(topList);
        } else if (types.equals(SIDE)) {
            cacheInMap.removeKey(sideList);
        }

        return Result.ok();
    }

    @Override
    public Result doLikes(Integer id, Integer action) {

        UserJwt userJwt = Holder.USER_JWT_THREAD_LOCAL.get();
        if (userJwt == null) {
            return Result.fail();
        }

        Integer userId = userJwt.getUserId();

        LambdaQueryWrapper<ArticleLikes> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ArticleLikes::getArticleId, id).eq(ArticleLikes::getMemberId, userId);
        ArticleLikes record = articleLikesMapper.selectOne(queryWrapper);
        if (record == null && action == 1) {
            //添加点赞
            ArticleLikes likes = new ArticleLikes();
            likes.setArticleId(id);
            likes.setMemberId(userId);
            articleLikesMapper.insert(likes);
        } else {
            //软删除 取消点赞
            articleLikesMapper.deleteById(record.getId());
        }

        return Result.ok();
    }

    @Override
    public Result<IPage<ArticleVo>> getByTag(Integer tagId, Integer pageNo, Integer pageSize) {
        Page<ArticleVo> page = new Page<>();
        page.setSize(pageSize);
        page.setCurrent(pageNo);

        List<ArticleVo> list = articleMapper.selectListPage(page, tagId);
        page.setRecords(list);
        return Result.ok(page);
    }

    @Override
    public Result cleanCache() {
        doCleanCache();
        return Result.ok();
    }

    private void doCleanCache() {
        cacheInMap.removeKey(sideList);
        cacheInMap.removeKey(hotList);
        cacheInMap.removeKey(topList);
        cacheInMap.removeKey(newList);
    }

    @Override
    public Result<IPage<Article>> list(String name, Integer categoryId, Integer status, Integer pageNo, Integer pageSize) {
        Page<Article> page = new Page<>();
        page.setSize(pageSize);
        page.setCurrent(pageNo);

        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.hasLength(name)) {
            queryWrapper.like(Article::getTitle, name);
        }
        if (categoryId != null) {
            queryWrapper.eq(Article::getCategoryId, categoryId);
        }
        queryWrapper.eq(Article::getDeleted, 0);

        if (status != null) {
            queryWrapper.eq(Article::getStatus, status);
        }

        queryWrapper.orderByDesc(Article::getId);

        IPage<Article> list = articleMapper.selectPage(page, queryWrapper);

        return Result.ok(list);
    }

    @Override
    public Result<Article> getById(Serializable id) {
        Article article = articleMapper.selectById(id);
        ArticleDetail articleDetail = articleDetailMapper.selectById(id);
        if (article == null)
            return Result.fail("找不到文章");
        if (articleDetail != null) {
            article.setContent(articleDetail.getContent());
            article.setDownAddress(articleDetail.getDownAddress());
        }

        List<Tag> tags = tagArticleMapper.selectListByArticleId(article.getId());
        article.setTags(tags);

        Article update = new Article();
        update.setId(article.getId());
        update.setBrowse(article.getBrowse() == null ? 1 : article.getBrowse() + 1);
        articleMapper.updateById(update);

        return Result.ok(article);
    }

    @Override
    public Result<String> getDownloadInfoById(Serializable id, String code) {

        Object obj = valueOperations.get(Constants.VERIFY_CODE);
//        Object obj = redisTemplate.opsForValue().get("code:" + code.trim());
        if (obj == null || !code.equals(obj.toString())) {
            return Result.fail("验证码错误");
        }

        ArticleDetail articleDetail = articleDetailMapper.selectById(id);
        if (articleDetail == null) {
            return Result.fail("找不到文章");
        }

        Article article = articleMapper.selectById(id);

        Article update = new Article();
        update.setId(articleDetail.getId());
        update.setDownTimes(article.getDownTimes() == null ? 1 : article.getDownTimes() + 1);
        articleMapper.updateById(update);

        return Result.ok(articleDetail.getDownAddress());
    }

    @Override
    public Result add(Article article) {

        articleMapper.insert(article);

        Integer id = article.getId();

        ArticleDetail detail = new ArticleDetail();
        detail.setId(id);
        detail.setContent(article.getContent());
        detail.setDownAddress(article.getDownAddress());
        articleDetailMapper.insert(detail);

        String[] tagIds = article.getTagIds();
        if (tagIds != null) {
            for (String tagId : tagIds) {
                TagArticle tagArticle = new TagArticle();
                tagArticle.setArticleId(id);
                tagArticle.setTagId(Integer.valueOf(tagId));
                tagArticleMapper.insert(tagArticle);
            }
        }

        return Result.ok();
    }

    @Override
    public Result updateById(Article article) {

        articleMapper.updateById(article);

        //更新文章详情
        updateArticleDetail(article);

        //添加 或 删除 文章 标签
        addOrUpdateArticleTag(article);

        //如果是下架或删除，则删除缓存
        if (article.getStatus() != null || article.getDeleted() != null) {
            doCleanCache();
        }

        return Result.ok();
    }

    private void updateArticleDetail(Article article) {
        ArticleDetail detail = new ArticleDetail();
        detail.setId(article.getId());
        detail.setContent(article.getContent());
        detail.setDownAddress(article.getDownAddress());
        articleDetailMapper.updateById(detail);
    }

    private void addOrUpdateArticleTag(Article article) {

        Integer id = article.getId();
        String[] tagIds = article.getTagIds();

        LambdaQueryWrapper<TagArticle> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TagArticle::getArticleId, id);
        List<TagArticle> list = tagArticleMapper.selectList(queryWrapper);

        if (tagIds == null || tagIds.length == 0) {
            if (list != null) {
                for (TagArticle tagArticle : list) {
                    tagArticleMapper.deleteById(tagArticle.getArticleId());
                }
            }
            return;
        }

        int[] updateTagIds = Arrays.stream(tagIds).mapToInt(Integer::valueOf).toArray();

        for (int tagId : updateTagIds) {
            boolean exist = false;
            for (TagArticle tagArticle : list) {
                if (tagArticle.getTagId() == tagId) {
                    //已存在  不操作
                    exist = true;
                    break;
                }
            }

            if (!exist) {
                //不存在 添加tag
                TagArticle tagArticle = new TagArticle();
                tagArticle.setArticleId(id);
                tagArticle.setTagId(tagId);
                tagArticleMapper.insert(tagArticle);
            }
        }

        for (TagArticle tagArticle : list) {
            boolean exist = false;
            for (int tagId : updateTagIds) {
                Integer tid = Integer.valueOf(tagId);
                if (tagArticle.getTagId() == tid) {
                    //已存在  不操作
                    exist = true;
                    break;
                }
            }
            if (!exist) {
                //不存在 删除tag
                tagArticleMapper.deleteById(tagArticle.getId());
            }
        }
    }

    @Override
    public Result deleteByIds(Set<Integer> ids) {
        for (Integer id : ids) {
            articleMapper.deleteById(id);
        }
        return Result.ok();
    }

    @Override
    public Result setCode(String code) {
        valueOperations.set(Constants.VERIFY_CODE, code);
        log.info("set_code=" + code);
        return Result.ok();
    }

    @Override
    public Result getCode() {
        String vcode;
        Object obj = valueOperations.get(Constants.VERIFY_CODE);
        if (obj == null) {
            vcode = "1024";
        } else {
            vcode = obj.toString();
        }
        log.info("get_code=" + vcode);
        return Result.ok(vcode);
    }

}
